#include "LogTableMgr.h"
#include "FileSys/FileSys.h"
#include "Log/LogFile.h"
#include <string.h>
#include <stdio.h>

bool CLogTableMgr::Init()
{
    int cachenum = 20;
    string apppath;
    if (!W_GetAppPath(apppath))
    {
        //
        return false;
    }
    string configpath = apppath + "/ModLogRes/LogConfig.ini";
    CIniFile2 iniFile(configpath.c_str());
    if (!iniFile.LoadFromFile())
    {
        cachenum = iniFile.ReadInteger("Params", "cachenum", 20);
    }

    return LoadTables();
}

bool CLogTableMgr::LoadTables()
{
    map<string, LogCache*>::iterator it;
    for (it = logs.begin(); it != logs.end(); it++)
    {
        delete it->second;
    }
    logs.clear();

    string sAppPath;
    if (!W_GetAppPath(sAppPath))
    {
        //
        return false;
    }
    string folderPath = sAppPath + "/ModLogRes/Tables/";

    logs.clear();

    CompareResult files;
	List_Files(folderPath.c_str(), files);

    for (size_t i = 0; i < files.size(); i++)
    {
        string szFileName = string(folderPath) + files[i].m_szFileName;
        AddLogTable(szFileName.c_str());
    }

    Log(LOG_NORMAL, "Load %d tables.\n", logs.size());
    return true;
}

LogCache* CLogTableMgr::GetLogCache(const char* tbName)
{
    std::map<string, LogCache*>::iterator iter = logs.find(tbName);
    if (iter == logs.end())
    {
        return NULL;
    }
    return iter->second;
}

/*

*/
bool CLogTableMgr::AddLogTable(const char* szFileName)
{
    CIniFile2 iniFile(szFileName);
    if (!iniFile.LoadFromFile())
    {
        return false;
    }

    //
    CDBTable logTable;
    string tableName = iniFile.ReadString("GLOBAL", "table_name", "");
    logTable.SetTableName(tableName.c_str());
    logTable.SetFieldNum(iniFile.ReadInteger("GLOBAL", "field_num", -1));

    if (logTable.GetFieldNum() > 99)
    {
        //too many fields
        Log(LOG_ERROR, "Too many fields with file %s.\n", szFileName);
        return false;
    }

    std::vector<ValueItem> vectFields;
    iniFile.ReadSectionValues("FIELDS", vectFields);

    if (logTable.GetFieldNum() != (int)vectFields.size())
    {
        //the num of fields does not match the listed fields num
        Log(LOG_ERROR, "Field's num don't match with file %s.\n", szFileName);
        return false;
    }

    for (size_t i = 0; i < vectFields.size(); i++)
    {
        int type;
        for (type = 0; type < EFT_NUM; type++)
        {
            if (strcmp(g_arrFieldTypeStr[type], vectFields[i].value.c_str()) == 0)
            {
                break;
            }
        }

        if (type >= EFT_NUM || type < 0)
        {
            //invalid column type
            Log(LOG_ERROR, "Unknown type with file %s.\n", szFileName);
            return false;
        }

        logTable.SetFieldType(i, type);
        logTable.SetFieldName(i, vectFields[i].name.c_str());
    }

    logTable.FormatInsertSQL();

    LogCache *logcache = new LogCache;
    logcache->table = logTable;
    logcache->recordnum = 0;
    logcache->starttime = time(NULL);
    logcache->sqlstr = logTable.GetInsertSQL();
    logs.insert(make_pair<string, LogCache*>(logTable.GetTableName(), logcache));

    return true;
}

void CLogTableMgr::TraverseLogCache(TraverseFunc func, void* param)
{
    map<string, LogCache*>::iterator it;
    for (it = logs.begin(); it != logs.end(); it++)
    {
        func(it->second, param);
    }
}
